//
// Created by macos on 2021/11/23.
//

#include "timer.h"

#define STOPFLAG 0
#define RUNFLAG 1

static int tick = 1000 * 1000;
static struct task_item head = {
        .next = NULL,
};
static pthread_t loop_thread;
static int flag = STOPFLAG;
static int tasknum  = 0;

void timer_set_ticker(int val){
    tick = val;
}

void* timer_event_loop(void* arg){

    struct task_item *task = head.next;
    struct task_item *pretask = &head;

    while(flag == RUNFLAG && tasknum > 0){

        while(task != NULL){
            if(task->counter == 0){ // it is time for doing task
                if(task->flag == STOPFLAG){ // task is not created
                    if(0 != pthread_create(&(task->th), NULL, task->task, task->arg)){ // do a task
                        printf("Failed to create user's task");
                    }
                    else{
                        task->flag = RUNFLAG;
                    }
                }
                else{
                    if(0 != pthread_kill(task->th, 0)){ // current task is completed
                        if(task->autoreset == AUTORESET){ // repeat execute
                            task->counter = task->init_counter;
                            task->flag = STOPFLAG;
                        }
                        else{ // delete a task
                            pretask->next = task->next;
                            free(task);
                            task = pretask->next;
                            tasknum--;
                            continue;
                        }
                    }
                }
            }
            else{
                task->counter--;
            }
            pretask = pretask->next;
            task = task->next;
        }

        usleep(tick); // sleep a tick
        task = head.next;
        pretask = &head;

    }

    flag = STOPFLAG;

}

void timer_add_task(timer_task_t task, int val, int autoreset, void *arg){
    struct task_item *node;

    node = (struct task_item*)malloc(sizeof(struct task_item));
    node->next = head.next;
    head.next = node;

    node->arg = arg;
    node->counter = val;
    node->init_counter = val;
    node->task = task;
    node->flag = STOPFLAG;
    node->autoreset = autoreset;

    tasknum++;

}

void timer_wait(){

    pthread_join(loop_thread, NULL);

}

void timer_stop(){
    flag = STOPFLAG;
}

void timer_start(){

    flag = RUNFLAG;
    if(0 != pthread_create(&loop_thread, NULL, timer_event_loop, NULL)){
        printf("Failed to create loop task.\n");
    }

}
